package com.yeskery.nut.core;

import com.yeskery.nut.util.EnvironmentUtils;
import com.yeskery.nut.util.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Logger;

/**
 * 默认系统环境接口实现类
 * @author sprout
 * @version 1.0
 * 2022-07-09 10:52
 */
public class DefaultEnvironment implements Environment {

    /** 日志对象 */
    private static final Logger logger = Logger.getLogger(DefaultEnvironment.class.getName());

    /** 默认的环境名 */
    private static final String DEFAULT_NAME = "default";

    /** 默认的配置名 */
    private static final String DEFAULT_PROPERTIES_NAME = "application";

    /** 默认的配置后缀 */
    private static final String DEFAULT_PROPERTIES_POSTFIX = ".properties";

    /** 默认的配置分隔符 */
    private static final String DEFAULT_PROPERTIES_SEPARATOR = "-";

    /** Nut配置环境名称 */
    private static final String NUT_SERVER_ENV_NAME = "server.env";

    /** 环境配置文件缓存 */
    private final Map<String, Properties> envPropertiesCache = new HashMap<>();

    /** 环境名称 */
    private String envName;

    /**
     * 构建默认系统环境接口实现类
     * @param envName 环境名称
     */
    public DefaultEnvironment(String envName) {
        this.envName = envName;
    }

    /**
     * 构建默认系统环境接口实现类
     */
    public DefaultEnvironment() {
        this(true);
    }

    /**
     * 构建默认系统环境接口实现类
     * @param logIfNotFound 如果默认配置文件不存在，是否输出日志
     */
    public DefaultEnvironment(boolean logIfNotFound) {
        Properties properties = getMainEnvProperties(logIfNotFound);
        String profiles = properties.getProperty(NUT_SERVER_ENV_NAME);
        if (!StringUtils.isEmpty(profiles)) {
            this.envName = profiles.toLowerCase();
        }
    }

    @Override
    public String getEnvName() {
        if (StringUtils.isEmpty(envName)) {
            return DEFAULT_NAME;
        }
        return envName;
    }

    @Override
    public Properties getMainEnvProperties() {
        return loadMainEnvProperties(DEFAULT_PROPERTIES_NAME);
    }

    /**
     * 获取系统主配置键值对
     * @param logIfNotFound 如果未找到资源时是否输出日志
     * @return 系统主配置键值对
     */
    public Properties getMainEnvProperties(boolean logIfNotFound) {
        return loadMainEnvProperties(DEFAULT_PROPERTIES_NAME, logIfNotFound);
    }

    @Override
    public Properties loadMainEnvProperties(String propertiesPath) {
        return loadMainEnvProperties(propertiesPath, true);
    }

    /**
     * 加载系统主配置键值对
     * @param propertiesPath 配置文件路径
     * @param logIfNotFound 如果未找到资源时是否输出日志
     * @return 系统主配置键值对
     */
    public Properties loadMainEnvProperties(String propertiesPath, boolean logIfNotFound) {
        // 读取默认配置文件
        Properties defaultProperties = new Properties();
        try {
            InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(
                    propertiesPath + DEFAULT_PROPERTIES_POSTFIX);
            if (inputStream != null) {
                defaultProperties.load(inputStream);
            } else {
                if (logIfNotFound) {
                    logger.info("Environment Profile [" + propertiesPath + DEFAULT_PROPERTIES_POSTFIX + "] NotFound.");
                }
            }
        } catch (IOException e) {
            throw new NutException("Environment Profile [default] Read Fail.", e);
        }
        return defaultProperties;
    }

    @Override
    public Properties getEnvProperties() {
        return loadEnvProperties(DEFAULT_PROPERTIES_NAME);
    }

    @Override
    public Properties loadEnvProperties(String propertiesPath) {
        if (propertiesPath.toLowerCase().endsWith(DEFAULT_PROPERTIES_POSTFIX)) {
            propertiesPath = propertiesPath.substring(0, propertiesPath.length() - DEFAULT_PROPERTIES_POSTFIX.length());
        }
        Properties properties = envPropertiesCache.get(propertiesPath);
        if (properties != null) {
            return properties;
        }
        // 读取默认配置文件
        Properties defaultProperties = loadMainEnvProperties(propertiesPath);

        // 读取环境变量配置文件
        if (StringUtils.isEmpty(envName)) {
            envPropertiesCache.put(propertiesPath, defaultProperties);
            return defaultProperties;
        }
        Properties envProperties = new Properties();
        try {
            InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(
                    propertiesPath + DEFAULT_PROPERTIES_SEPARATOR + envName + DEFAULT_PROPERTIES_POSTFIX);
            if (inputStream != null) {
                envProperties.load(inputStream);
            } else {
                logger.info("Environment Profile [" + propertiesPath + DEFAULT_PROPERTIES_SEPARATOR
                        + envName + DEFAULT_PROPERTIES_POSTFIX + "] NotFound.");
            }
        } catch (IOException e) {
            throw new NutException("Environment Profile [" + envName + "] Read Fail.", e);
        }
        if (envProperties.isEmpty()) {
            envPropertiesCache.put(propertiesPath, defaultProperties);
            return defaultProperties;
        }
        defaultProperties.putAll(envProperties);
        envPropertiesCache.put(propertiesPath, defaultProperties);
        updateEnvironmentValue(defaultProperties);
        return defaultProperties;
    }

    /**
     * 更新环境对象值
     * @param defaultProperties 默认配置对象
     */
    private void updateEnvironmentValue(Properties defaultProperties) {
        for (String name : defaultProperties.stringPropertyNames()) {
            String value = defaultProperties.getProperty(name);
            String originalValue = value;
            if (!StringUtils.isEmpty(value)) {
                Set<String> placeHolders = EnvironmentUtils.getPlaceHolders(value);
                for (String placeHolder : placeHolders) {
                    String placeHolderName = placeHolder.substring(2, placeHolder.length() - 1);
                    String placeValue = defaultProperties.getProperty(placeHolderName);
                    if (placeValue != null) {
                        value = value.replace(placeHolder, placeValue);
                    }
                }
            }
            if (!originalValue.equals(value)) {
                defaultProperties.put(name, value);
            }
        }
    }
}
